﻿using MRSite.Common.Configuration;
using MRSite.Common.Dependency;
using MRSite.Common.Extensions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MRSite.Common.Kernels
{
    public class KernelManager : IKernelManager
    {
        public KernelManager(IContainerManager containerManager)
        {
            _containerManager = containerManager;
        }

        public IReadOnlyList<KernelInfo> KernelInfos => _kernelInfos;

        public void Initialize(Type startupKernel)
        {
            _kernelInfos = new List<KernelInfo>();
            GetAllBaseOn(startupKernel);
        }

        private List<Type> GetAllBaseOn(Type startupKernel)
        {
            var list = new List<Type>();
            AddItems(list, startupKernel);
            var type = typeof(PreInitKernel);
            if (list.AddNotContained(type))
            {
                RegistTypeAndAddToList(type);
            }
            return list;
        }

        private void AddItems(List<Type> list, Type kernelType)
        {
            if (list.AddNotContained(kernelType))
            {
                RegistTypeAndAddToList(kernelType);
            }
            var baseKernerls = FindBaseOn(kernelType);
            foreach (var type in baseKernerls)
            {
                AddItems(list, type);
            }
        }

        private void RegistTypeAndAddToList(Type type)
        {
            if (!_containerManager.IsRegisted(type))
            {
                _containerManager.Regist(type);
            }
            var instance = _containerManager.Resolver<BaseKernel>(type);
            instance.CtnManager = _containerManager;
            instance.ConfigurationManager = _containerManager.Resolver<IConfigurationManager>();
            var kernelInfo = new KernelInfo(type, instance);
            _kernelInfos.AddNotContained(kernelInfo);
        }

        private List<Type> FindBaseOn(Type kernelType)
        {
            var list = new List<Type>();
            if (kernelType.IsDefined(typeof(ShanYuBaseOnAttribute), true))
            {
                var attrs = kernelType.GetCustomAttributes(typeof(ShanYuBaseOnAttribute), true)
                    .Cast<ShanYuBaseOnAttribute>();
                foreach (var item in attrs)
                {
                    foreach (var type in item.BaseOnTypes)
                    {
                        list.Add(type);
                    }
                }
            }
            return list;
        }

        public void StartAll()
        {
            var sortedList = new List<KernelInfo>();
            getSortedList(_kernelInfos, sortedList);

            sortedList.ForEach(x => x.Instance.PreInit());
            sortedList.ForEach(x => x.Instance.Init());
            sortedList.ForEach(x => x.Instance.PostInit());

        }

        private void getSortedList(List<KernelInfo> kernelInfos, List<KernelInfo> sortedList)
        {
            foreach (var item in kernelInfos)
            {
                if (item.BaseOnKernels != null)
                {
                    getSortedList(item.BaseOnKernels, sortedList);
                }
                if (kernelInfos.Contains(item))
                {
                    sortedList.Remove(item);
                    sortedList.Insert(0, item);
                }
                else
                {
                    sortedList.Insert(0, item);
                }
            }
        }

        private IContainerManager _containerManager;
        private List<KernelInfo> _kernelInfos;
    }
}
